package com.iotstudio.embeddedcloudplatform.shiro.Filter;

import com.iotstudio.embeddedcloudplatform.constants.HttpParamKey;
import com.iotstudio.embeddedcloudplatform.enums.ResultEnum;
import com.iotstudio.embeddedcloudplatform.shiro.token.StatelessAuthenticationToken;
import com.iotstudio.embeddedcloudplatform.util.web.CookieUtil;


import com.iotstudio.embeddedcloudplatform.util.web.ResponseUtil;
import com.iotstudio.embeddedcloudplatform.util.web.ResultVOUtil;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class StatelessAccessControllerFilter extends AccessControlFilter {

    private static final Logger LOGGER = LoggerFactory.getLogger(StatelessAccessControllerFilter.class);
    /**
     * 先执行：isAccessAllowed 再执行onAccessDenied
     * isAccessAllowed：表示是否允许访问；mappedValue就是[urls]配置中拦截器参数部分，
     * 如果允许访问返回true，否则false；
     * 如果返回true的话，就直接返回交给下一个filter进行处理。
     * 如果返回false的话，会往下执行onAccessDenied
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception {
        LOGGER.info("StatelessAuthcFilter.isAccessAllowed()");
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
        try {
            //获取token
            String token = httpServletRequest.getHeader(HttpParamKey.CLIENT_DIGEST);
            String[] tokenArray = token.split("\\.");
            if (tokenArray.length != 2){
                LOGGER.error(ResultEnum.PARAM_ERROR.getMessage());
                onParamError(httpServletResponse, ResultEnum.PARAM_ERROR.getMessage());
                return false;
            }
            //1、客户端生成的消息摘要
            String clientDigest = tokenArray[1];
            //2、客户端传入的用户身份
            String clientId = tokenArray[0];
            //如果参数为空则返回错误信息
            if (clientDigest == null || clientId == null){
                String nullParamMsg = "已拦截请求！"+ HttpParamKey.CLIENT_ID + "或" + HttpParamKey.CLIENT_DIGEST+ "不能为空！";
                LOGGER.error(nullParamMsg);
                onParamError(httpServletResponse, nullParamMsg);
                return false;
            }
            //参数不为空打印信息
            LOGGER.info(HttpParamKey.CLIENT_ID + ":" + clientId + "," + HttpParamKey.CLIENT_DIGEST + ":" + clientDigest);
            //3、添加用于生成消息摘要的参数列表,添加一个用户私有资源授权的参数
//            Map<String,String> params = new HashMap<>();
//            params.put("isOwner",Boolean.toString(isOwner(httpServletRequest,clientId)));
            //4、生成无状态Token
            StatelessAuthenticationToken statelessAuthenticationToken = new StatelessAuthenticationToken(clientId,clientDigest);
            //5、委托给Realm进行登录
            getSubject(servletRequest, servletResponse).login(statelessAuthenticationToken);
            //登录成功后设置header保存登录状态
            CookieUtil.addCookie(httpServletResponse,HttpParamKey.CLIENT_ID, clientId);
            CookieUtil.addCookie(httpServletResponse,HttpParamKey.CLIENT_DIGEST,clientDigest);
            //跨域设置(调试用)
            httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.info("登录异常");
            onLoginFail(httpServletResponse);
            return false;
        }
        return true;
    }

    /**
     * onAccessDenied：表示当访问拒绝时是否已经处理了；如果返回true表示需要继续处理；
     * 如果返回false表示该拦截器实例已经处理了，将直接返回即可。
     */
    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException {
        LOGGER.info("StatelessAuthcFilter.onAccessDenied()");
        return false;
    }

    //登录失败时默认返回401 状态码
    private void onLoginFail(ServletResponse response) throws IOException {
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        ResponseUtil.toJson(
                httpServletResponse,
                ResultVOUtil.error(ResultEnum.LOGIN_FAILED)
                );
    }

    /**
     * 参数不正确返回错误信息
     * @param response
     * @param msg 错误消息
     * @throws IOException
     */
    private void onParamError(HttpServletResponse response, String msg) throws IOException{
        response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
        ResponseUtil.toJson(
                response,
                ResultVOUtil.error(ResultEnum.PARAM_ERROR.getCode(), msg)
        );
    }
}
